/*
 * LibSVMDemo.cpp
 *
 *  Created on: 2013-6-4
 *      Author: wangyu
 */
#include "Comment.h"
#include "md5.h"

int main() {
	vector<ImagePathInfo> images;
	loadImages(trainFolderPath, images);
	cout << images.size() << endl;
//	getSIFTImagesFeature(images, imageSIFTFeatureFileName);
//	makeSIFTBOWVocabulary(images, imageSIFTFeatureFileName, siftBOWVocabulary);
//	makeSIFTBOWFeature(images, siftBOWVocabulary, siftBOWFeature);
	return 0;
}

/***load under path .jpg file path and filename on imageList**/
void loadImages(const char *path, vector<ImagePathInfo>& imageList) {
	struct dirent* ent = NULL;
	DIR *pDir;
	pDir = opendir(path);
	if (pDir == NULL) {
		return;
	}
	std::string fullDirPath;
	while (NULL != (ent = readdir(pDir))) {
		std::string _path(path);
		std::string _dirName(ent->d_name);
		fullDirPath = _path + "/" + _dirName;
		if (ent->d_type == 8) {
			int bol = fullDirPath.find(".jpg", 0);
			if (bol > 0) {
//				cout << fullDirPath << endl;
				ImagePathInfo im;
				im.path = _path;
				im.fullname = fullDirPath;
				imageList.push_back(im);
			}
		} else {
			if (strcmp(ent->d_name, ".") == 0
					|| strcmp(ent->d_name, "..") == 0) {
				continue;
			}
			loadImages(fullDirPath.c_str(), imageList);
		}
	}
}

/********get SIFT feature and write to files***********/
void getSIFTImagesFeature(vector<ImagePathInfo> imageList, char *filefullname) {

	DescriptorExtractor *pExtractor = new SiftDescriptorExtractor;
	FeatureDetector *pDetector = new SiftFeatureDetector;
	MD5 md5;
	FileStorage fs(filefullname, FileStorage::WRITE);

	for (int index = 0; index < (int) imageList.size(); index++) {

		cout << "SIFT" << index;
		string imgName = imageList.at(index).fullname;

		Mat img = imread(imgName);
		vector<KeyPoint> mKeypoints;
		Mat mDescriptors;

		pDetector->detect(img, mKeypoints);
		pExtractor->compute(img, mKeypoints, mDescriptors);

		md5.reset();
		md5.update(imgName);
		string name = "i" + md5.toString();
		cout << " i" << md5.toString() << endl;

		fs << name << mDescriptors;

		mKeypoints.clear();
		mDescriptors.release();
		img.release();
	}
	fs.release();
}
/********get SURF feature and write to files***********/
void getSURFImagesFeature(vector<ImagePathInfo> imageList, char *filefullname) {

	DescriptorExtractor *pExtractor = new SurfDescriptorExtractor;
	FeatureDetector *pDetector = new SurfFeatureDetector;
	MD5 md5;
	FileStorage fs(filefullname, FileStorage::WRITE);

	for (int index = 0; index < (int) imageList.size(); index++) {

		cout << "SURF" << index;
		string imgName = imageList.at(index).fullname;

		Mat img = imread(imgName);
		vector<KeyPoint> mKeypoints;
		Mat mDescriptors;

		pDetector->detect(img, mKeypoints);
		pExtractor->compute(img, mKeypoints, mDescriptors);

		md5.reset();
		md5.update(imgName);
		string name = "i" + md5.toString();
		cout << " i" << md5.toString() << endl;

		fs << name << mDescriptors;

		mKeypoints.clear();
		mDescriptors.release();
		img.release();
	}
	fs.release();
}

void makeSIFTBOWVocabulary(vector<ImagePathInfo> imageList,
		char *featurefilename, char *bowfilename) {
	MD5 md5;
	BOWKMeansTrainer bow_trainer(c_nBowClusterCount,
			cvTermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 0.1));
	FileStorage rfs(featurefilename, FileStorage::READ);
	for (int index = 0; index < (int) imageList.size(); index++) {
		md5.reset();
		md5.update(imageList.at(index).fullname);
		Mat mDescriptors;
		rfs["i" + md5.toString()] >> mDescriptors;
		if (!mDescriptors.empty()) {
			bow_trainer.add(mDescriptors);
			cout << index << " load " << md5.toString() << endl;
		} else {
			cout << "could't load " << md5.toString() << endl;
		}
		mDescriptors.release();
	}
	rfs.release();
	cout << "load SIFT end and start make bow vocabulary!" << endl;
	Mat m_mBowSiftVocabulary = bow_trainer.cluster();
	FileStorage fs(bowfilename, FileStorage::WRITE);
	fs << "vocabulary" << m_mBowSiftVocabulary;
	bow_trainer.clear();
	fs.release();
	cout << "make bow vocabulary end!" << endl;
}

void makeSIFTBOWFeature(vector<ImagePathInfo> imageList, char *bowfilename,
		char *siftbowfile) {

	Ptr<DescriptorExtractor> mDE = DescriptorExtractor::create("SIFT");
	Ptr<DescriptorMatcher> mDM = DescriptorMatcher::create("FlannBased");
	BOWImgDescriptorExtractor sift_bow_DE(mDE, mDM);

	cout << "load sift vocabulary" << endl;
	FileStorage rfs(bowfilename, FileStorage::READ);
	Mat m_mBowSiftVocabulary;
	rfs["vocabulary"] >> m_mBowSiftVocabulary;
	rfs.release();
	sift_bow_DE.setVocabulary(m_mBowSiftVocabulary);
	cout << "load sift vocabulary and set vocabulary end" << endl;

	MD5 md5;
	FileStorage fs(siftbowfile, FileStorage::WRITE);
	Ptr<FeatureDetector> mFD =  FeatureDetector::create("SIFT");
	cout << "make sift bow feature " << imageList.size() << endl;

	for (int index = 0; index < (int) imageList.size(); index++) {

		string imgName = imageList.at(index).fullname;
		cout << index << " name : " << imgName;

		Mat img = imread(imgName);
		vector<KeyPoint> keypoints;
		Mat *descriptor = new Mat;

		mFD->detect(img, keypoints);
		sift_bow_DE.compute(img, keypoints, *descriptor);

		md5.reset();
		md5.update(imgName);
		string name = "v" + md5.toString();
		fs << name << *descriptor;
		cout << " " << name << endl;

		img.release();
		keypoints.clear();
		descriptor->release();
	}
	fs.release();
	cout << "make sift bow feature end !" << endl;
}
